
#include "gsl_ext_function.h"
#include "gsl_ext_symbolic_function.h"
#include "GSLFunctionWrapper.h"
#include "GSLMinimizerWrapper.h"

#include <gsl/gsl_multimin.h>

GSLMinimizerWrapper::GSLMinimizerWrapper() : numIter_(0) { }

int GSLMinimizerWrapper::iterate()
{
  numIter_++;
  return iterate_();
}

GSLMinimizerWrapper_f::GSLMinimizerWrapper_f(gsl_multimin_fminimizer *m):
  GSLMinimizerWrapperT< gsl_multimin_fminimizer >(m) { }

void GSLMinimizerWrapper_f::destroyWrappedObject()
{
  gsl_multimin_fminimizer_free(minimizer_);
}

double GSLMinimizerWrapper_f::f() const
{
  return minimizer_->fval;
}

GSLMinimizerWrapper::Type GSLMinimizerWrapper_f::getType() const
{
  return GSLMinimizerWrapper::F;
}

string GSLMinimizerWrapper_f::getName() const
{
  return gsl_multimin_fminimizer_name(minimizer_);
}

gsl_vector *GSLMinimizerWrapper_f::gradient() const
{
  return NULL;
}

gsl_matrix *GSLMinimizerWrapper_f::Hessian() const
{
  return NULL;
}

void GSLMinimizerWrapper_f::set(const GSLFunctionWrapper &f,
                                const gsl_vector *x,
                                const gsl_vector *step_size)
{
  const GSLFunctionWrapper_f &f_wrapped = dynamic_cast< const GSLFunctionWrapper_f & >(f);
  gsl_multimin_fminimizer_set(minimizer_, f_wrapped, x, step_size);
}

double GSLMinimizerWrapper_f::size() const
{
  return gsl_multimin_fminimizer_size(minimizer_);
}

int GSLMinimizerWrapper_f::iterate_()
{
  return gsl_multimin_fminimizer_iterate(minimizer_);
};

GSLMinimizerWrapper_fdf::GSLMinimizerWrapper_fdf(gsl_multimin_fdfminimizer *m):
  GSLMinimizerWrapperT< gsl_multimin_fdfminimizer >(m) { }

void GSLMinimizerWrapper_fdf::destroyWrappedObject()
{
  gsl_multimin_fdfminimizer_free(minimizer_);
}

gsl_vector *GSLMinimizerWrapper_fdf::dx() const
{
  return minimizer_->dx;
}

double GSLMinimizerWrapper_fdf::f() const
{
  return minimizer_->f;
}

GSLMinimizerWrapper::Type GSLMinimizerWrapper_fdf::getType() const
{
  return GSLMinimizerWrapper::FDF;
}

string GSLMinimizerWrapper_fdf::getName() const
{
  return gsl_multimin_fdfminimizer_name(minimizer_);
}

gsl_vector *GSLMinimizerWrapper_fdf::gradient() const
{
  return minimizer_->gradient;
}

gsl_matrix *GSLMinimizerWrapper_fdf::Hessian() const
{
  return NULL;
}

void GSLMinimizerWrapper_fdf::set(const GSLFunctionWrapper &f,
                                  const gsl_vector *x,
                                  double step_size,
                                  double tol)
{
  const GSLFunctionWrapper_fdf &f_wrapped = dynamic_cast< const GSLFunctionWrapper_fdf & >(f);
  gsl_multimin_fdfminimizer_set(minimizer_, f_wrapped, x, step_size, tol);
}

int GSLMinimizerWrapper_fdf::iterate_()
{
  return gsl_multimin_fdfminimizer_iterate(minimizer_);
};

GSLMinimizerWrapper_fd2f::GSLMinimizerWrapper_fd2f(gsl_ext_multimin_fd2fminimizer *m):
  GSLMinimizerWrapperT< gsl_ext_multimin_fd2fminimizer >(m) { }

void GSLMinimizerWrapper_fd2f::destroyWrappedObject()
{
  gsl_ext_multimin_fd2fminimizer_free(minimizer_);
}

gsl_vector *GSLMinimizerWrapper_fd2f::dx() const
{
  return minimizer_->dx;
}

double GSLMinimizerWrapper_fd2f::f() const
{
  return minimizer_->f;
}

string GSLMinimizerWrapper_fd2f::getName() const
{
  return gsl_ext_multimin_fd2fminimizer_name(minimizer_);
}

GSLMinimizerWrapper::Type GSLMinimizerWrapper_fd2f::getType() const
{
  return GSLMinimizerWrapper::FD2F;
}

gsl_vector *GSLMinimizerWrapper_fd2f::gradient() const
{
  return minimizer_->gradient;
}

gsl_matrix *GSLMinimizerWrapper_fd2f::Hessian() const
{
  return minimizer_->hessian;
}

void GSLMinimizerWrapper_fd2f::set(const GSLFunctionWrapper &f,
                                   const gsl_vector *x,
                                   double step_size,
                                   double tol)
{
  const GSLFunctionWrapper_fd2f &f_wrapped = dynamic_cast< const GSLFunctionWrapper_fd2f & >(f);
  gsl_ext_multimin_fd2fminimizer_set(minimizer_, f_wrapped, x, step_size, tol);
}

int GSLMinimizerWrapper_fd2f::iterate_()
{
  return gsl_ext_multimin_fd2fminimizer_iterate(minimizer_);
}
